package app.rci.util;


import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Collection;
import java.util.List;
import java.lang.reflect.InvocationTargetException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.beanutils.BeanUtilsBean;

import app.rci.config.SessionScopeConstants;
import app.rci.util.MygsetLocalPicker;
import net.sourceforge.stripes.localization.LocalizationUtility;
import net.sourceforge.stripes.validation.LocalizableError;
import net.sourceforge.stripes.action.LocalizableMessage;

/**
 * This class content the common method for checking solution.
 *
 * @author johnlaw
 */
public class Utils {

//	/**
//	 * Change String to date
//	 * @param date Date in string
//	 * @param pattern pattern of the date
//	 * @return Date
//	 * @throws ParseException
//	 */
//    public static Date stringToDate(String date, String pattern) throws ParseException {
//    	return (new SimpleDateFormat(pattern)).parse(date); 
//    }
//
//    /**
//     * Change date to string
//     * @param date Date
//     * @param pattern pattern of date
//     * @return Date in string with the given pattern
//     */
//	public static String dateToString(Date date, String pattern) {
//		return new SimpleDateFormat(pattern).format(date);
//	}

     static {
        beanUtils = BeanUtilsBean.getInstance();
    }

    /**
     * Check whether it is integer or not
     *
     * @param value A String value
     * @return true if it is integer otherwise false
     */
    public static boolean isIntNumber(String value) {

        boolean result = false;

        try {
            Integer.parseInt(value);
            result = true;
        } catch (Exception e) {
            result = false;
        }
        return result;
    }

    /**
     * Check whether it is double or not
     *
     * @param value A String value
     * @return true if it is double otherwise false
     */
    public static boolean isDoubleNumber(String value) {

        boolean result = false;

        try {
            value = value.replaceAll(",", "");
            Double.parseDouble(value);
            result = true;
        } catch (Exception e) {
            result = false;
        }
        return result;
    }

    /**
     * Convert a double number to string with format "##,###,##0.00"
     *
     * @param number
     * @return
     * @author HaiVH
     */
    public static String formatDoubleToCurrency(double number) {
        String str = "";
        try {
            NumberFormat formatter = new DecimalFormat("##,###,##0.00");
            str = number == 0 ? "0.00" : formatter.format(formatDouble(number, 2));
        } catch (Exception e) {
            System.err.println("ERROR = " + e);
        }
        return str;
    }

    /**
     * Convert a double number to currency string with format "###,###.##"
     *
     * @param number
     * @return String
     * @author Wisnu created on 10-08-2009
     */
    public static String formatDoubleToCurrency2(double number) {
        String str = "0.00";
        try {
            if (number != 0) {
                NumberFormat nf = NumberFormat.getNumberInstance(new Locale("en", "US"));
                DecimalFormat df = (DecimalFormat) nf;
                df.applyPattern("###,##0.00");
                str = df.format(formatDouble(number, 2));
            }
        } catch (Exception e) {
            System.err.println("ERROR = " + e);
        }
        return str;
    }

    public static double convertStringToDouble(String strNumber) {
        if (!Utils.isNullorEmptyString(strNumber)) {
            strNumber = strNumber.replaceAll(",", "");
            try {
                return Double.parseDouble(strNumber);
            } catch (NumberFormatException e) {
                System.err.println("ERROR = " + e);
            }
        }
        return 0;
    }

    public static int convertStringToInteger(String strNumber) {
        if (!Utils.isNullorEmptyString(strNumber)) {
            strNumber = strNumber.replaceAll(",", "");
            try {
                return Integer.parseInt(strNumber);
            } catch (NumberFormatException e) {
                System.err.println("ERROR = " + e);
            }
        }
        return 0;
    }

    /**
     * format a double with n digit after point
     *
     * @param number - number to format
     * @param digit  - number of digit after point
     * @return number was formated
     * @author HaiVH
     */

    public static double formatDouble(double number, int digit) {
        long pow = (long) Math.pow(10, digit);
        return (((double) Math.round(pow * number)) / pow);
    }

    public static boolean isNullorEmptyString(String value) {

        return value == null || value.length() == 0 || value=="";
    }

    /**
     * Convert an Object to String
     * if this Object is null, return ""
     *
     * @param obj
     * @return String
     * @author VuTrongDat
     */
    public static String toStringSpecial(Object obj) {
        if (obj != null) {
            return "" + obj;
        } else {
            return "";
        }
    }

    /**
     * format Double object to String object with 2 digits after decimal point
     *
     * @param d
     * @return String object after formating
     * @author Duc
     */
    public static String getStrDoubleWithScale2(Double d) {
        return getStrDoubleWithScale(d == null ? 0 : d.doubleValue(), 2);
    }

    /**
     * format double value to String object with 2 digits after decimal point
     *
     * @param d
     * @return String object after formating
     * @author Duc
     */
    public static String getStrDoubleWithScale2(double d) {
        return getStrDoubleWithScale(d, 2);
    }

    /**
     * format Double object to String object with 'scale' digits after decimal point
     *
     * @param d
     * @return String object after formating
     * @author Duc
     */
    public static String getStrDoubleWithScale(Double d, int scale) {
        return getStrDoubleWithScale(d == null ? 0 : d.doubleValue(), scale);
    }

    /**
     * format double value to String object with 'scale' digits after decimal point
     *
     * @param d
     * @param scale
     * @return String object after formating
     * @author Duc
     */
    public static String getStrDoubleWithScale(double d, int scale) {
        BigDecimal bigDecimal = new BigDecimal(d);
        bigDecimal = bigDecimal.setScale(scale, BigDecimal.ROUND_HALF_DOWN);
        DecimalFormat decimalFormat = new DecimalFormat("#,##0.##");
        String sReturn = decimalFormat.format(bigDecimal);
        System.out.println("sReturn = " + sReturn);
        int intScale = scale;
        int index = sReturn.indexOf(".");
        if (index > -1) {
            try {
                intScale = intScale - sReturn.substring(index + 1).length();
            } catch (Exception e) {
                intScale = 0;
            }
        }

        if (intScale > 0) {
            StringBuffer str1 = new StringBuffer();
            for (int i = 0; i < intScale; i++) {
                str1.append("0");
            }
            sReturn = sReturn + (index > -1 ? "" : ".") + str1.toString();
        }
        return sReturn;
    }

    /**
     * Using for large number
     * format big decimal value to String object with 2 digits after decimal point
     *
     * @param strNumber
     * @return String object after formating
     * @author Duc
     */
    public static String getStrDoubleWithScale2(String strNumber) {
        return getStrDoubleWithScale(strNumber, 2);
    }

    /**
     * Using for large number
     * format big decimal value to String object with 'scale' digits after decimal point
     *
     * @param strNumber
     * @param scale
     * @return String object after formating
     * @author Duc
     */
    public static String getStrDoubleWithScale(String strNumber, int scale) {
        BigDecimal bigDecimal = convertStringToBigDecimal(strNumber);
        bigDecimal = bigDecimal.setScale(scale, BigDecimal.ROUND_HALF_DOWN);
        DecimalFormat decimalFormat = new DecimalFormat("#,##0.##");
        String sReturn = decimalFormat.format(bigDecimal);
        int intScale = scale;
        int index = sReturn.indexOf(".");
        if (index > -1) {
            try {
                intScale = intScale - sReturn.substring(index + 1).length();
            } catch (Exception e) {
                intScale = 0;
            }
        }

        if (intScale > 0) {
            StringBuffer str1 = new StringBuffer();
            for (int i = 0; i < intScale; i++) {
                str1.append("0");
            }
            sReturn = sReturn + (index > -1 ? "" : ".") + str1.toString();
        }
        return sReturn;
    }

    /**
     * Using for large number
     * convert a string to BigDecimal object
     *
     * @param strNumber
     * @return
     * @author Duc
     */
    public static BigDecimal convertStringToBigDecimal(String strNumber) {
        if (!Utils.isNullorEmptyString(strNumber)) {
            strNumber = strNumber.replaceAll(",", "");
            try {
                return new BigDecimal(strNumber);
            } catch (NumberFormatException e) {
                System.err.println("ERROR = " + e);
            }
        }
        return BigDecimal.ZERO;
    }

    /**
     * to keep parameterName object with value to session
     *
     * @param request
     * @param parameterName
     * @param value
     */
    public static void setSessionAttribute(HttpServletRequest request, String parameterName, Object value) {
        if (request != null) {
            HttpSession session = request.getSession();
            session.setAttribute(parameterName, value);
        }
    }

    /**
     * to get parameterName object from session
     *
     * @param request
     * @param parameterName
     * @return
     */
    public static Object getSessionAttribute(HttpServletRequest request, String parameterName) {
        Object obj = null;
        if (request != null) {
            HttpSession session = request.getSession();
            obj = session.getAttribute(parameterName);
        }
        return obj;
    }

    /**
     * to get resource bundle depends on userLocale
     *
     * @param request
     * @param userLocale
     * @return
     */
    public static ResourceBundle getResouceBundle(HttpServletRequest request, Locale userLocale) {
        ResourceBundle rb = null;
        if (request != null) {
            rb = (ResourceBundle) getSessionAttribute(request, SessionScopeConstants.RESOURCE_BUNDLE);
            if (rb == null) {
                userLocale = (userLocale == null ? new Locale("en_US") : userLocale);
                rb = ResourceBundle.getBundle("StripesResources", userLocale);
                setSessionAttribute(request, SessionScopeConstants.RESOURCE_BUNDLE, rb);
            }
        }
        return rb;
    }

    /**
     * to display multi language on the screen - include error message & labels
     *
     * @param request
     * @param key
     * @return
     */
    public static String getI18nMessage(HttpServletRequest request, String key) {
        /*
        MygsetLocalPicker localPicker = new MygsetLocalPicker();
        Locale userLocale = localPicker.pickLocale(request);
        userLocale = (userLocale == null ? new Locale("en_US") : userLocale);
        return getResouceBundle(request, userLocale).getString(key);
        */
        Locale locale = request.getLocale();
        return LocalizationUtility.getErrorMessage(locale, key);

    }

    private static BeanUtilsBean beanUtils;

    /**
     * Copy value from all properties in src object to dest object as long as
     * property name is the same. Data type conversion is done automatically
     * using registered Converter
     *
     * @param dest -
     *             Destination object
     * @param src  -
     *             Source object
     */
    public static void copyBeanProperties(Object dest, Object src) {
        try {
            beanUtils.copyProperties(dest, src);
        } catch (IllegalAccessException e) {
            System.err.println("ERROR = " + e);
        } catch (InvocationTargetException e) {
            System.err.println("ERROR = " + e);
        }
    }

    /**
     * Copy value from all properties in src object to dest object as long as
     * property name is the same. Data type conversion is done automatically
     * using registered Converter. This method also try to copy value from
     * different property which specified in destPropNames and srcPropNames
     * using this mechanism:
     * <p/>
     * Value from property name specified in srcPropNames[n] will be copied to
     * property name specified in destPropNames[n]
     *
     * @param dest          -
     *                      Destination object
     * @param src           -
     *                      Source object
     * @param destPropNames -
     *                      Array of destination property names
     * @param srcPropNames  -
     *                      Array of source property names
     */
    public static void copyBeanProperties(Object dest, Object src,
                                          String[] destPropNames, String[] srcPropNames) {

        if (destPropNames.length != srcPropNames.length) {
            throw new RuntimeException(
                    "Array length in destPropNames and srcPropNames must be equal");
        }
        copyBeanProperties(dest, src);
        for (int i = 0; i < srcPropNames.length; i++) {
            try {
                beanUtils.setProperty(dest, destPropNames[i], beanUtils
                        .getProperty(src, srcPropNames[i]));
            } catch (IllegalAccessException e) {
                System.err.println("ERROR = " + e);
            } catch (InvocationTargetException e) {
                System.err.println("ERROR = " + e);
            } catch (NoSuchMethodException e) {
                System.err.println("ERROR = " + e);
            }
        }

    }

    /**
     * Copy property values from each element object in src collection to
     * element in dest collection using same mechanism with copyProperties.
     *
     * @param dest             -
     *                         Destination collection
     * @param src              -
     *                         Source collection
     * @param destElementClass -
     *                         Destination collection element class type
     */
    @SuppressWarnings("unchecked")
    public static void copyCollection(Collection dest, Collection src,
                                      Class destElementClass) {
        /*
         * Method name as string
         */

        try {
            for (int i = 0; i < src.size(); i++) {
                Object destElement = null;
                if (dest.size() <= i) {
                    destElement = destElementClass.newInstance();
                    dest.add(destElement);
                } else {
                    destElement = ((List) dest).get(i);
                }
                copyBeanProperties(destElement, ((List) src).get(i));
            }
        } catch (InstantiationException e) {
            System.err.println("ERROR = " + e);
        } catch (IllegalAccessException e) {
            System.err.println("ERROR = " + e);
        }
    }

    public static void main(String[] args) {

//		System.out.println(getStrDoubleWithScale(123213.0999, 2));
//		System.out.println(getStrDoubleWithScale(342342.14934, 2));
//		System.out.println(getStrDoubleWithScale(43242.018, 1));		    	       
//		System.out.println(getStrDoubleWithScale(43242.018, 0));
//		System.out.println(getStrDoubleWithScale(1.6401828999999998E7, 0));
//		System.out.println(getStrDoubleWithScale(Double.MAX_VALUE, 2));

        System.out.println(formatDoubleToCurrency(999999999999999.99));
//		System.out.println(getStrDoubleWithScale2(convertStringToDouble("0")));
//		System.out.println(getStrDoubleWithScale(convertStringToDouble("0"), 0));
//		System.out.println(getStrDoubleWithScale2(convertStringToDouble("999,999,999,999,999")));
//		System.out.println(getStrDoubleWithScale2(convertStringToDouble("999,999,999,999,999.99")));
        System.out.println(getStrDoubleWithScale2(convertStringToDouble("99,999,999,999,999.99")));
        System.out.println(convertStringToDouble("999,999,999,999,999.92"));
        System.out.println(getStrDoubleWithScale2(convertStringToDouble("999,999,999,999,999.92")));

        System.out.println(getStrDoubleWithScale2("999,999,999,999,999.94"));

//		System.out.println(getStrDoubleWithScale2("0"));
//		System.out.println(getStrDoubleWithScale("0", 0));
//		System.out.println(getStrDoubleWithScale2("999,999,999,999,999"));
//		System.out.println(getStrDoubleWithScale2("999,999,999,999,999.99"));
//		System.out.println(getStrDoubleWithScale2("99,999,999,999,999.99"));
//		System.out.println(getStrDoubleWithScale2(convertStringToDouble("999,999,999.99")));
//		System.out.println(getStrDoubleWithScale2(convertStringToDouble("999,999,999,999,999.99")));
	}

    public static double roundTwoDecimals(double d) {
        DecimalFormat twoDForm = new DecimalFormat("#.##");
        return Double.valueOf(twoDForm.format(d));
    }
}
